package com.duan.laugh.activiti.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.duan.laugh.activiti.constants.ActivitiConstants;
import com.duan.laugh.activiti.pojo.dto.CommentDto;
import com.duan.laugh.activiti.pojo.dto.TaskDTO;
import com.duan.laugh.activiti.service.ActTaskService;
import com.duan.laugh.common.security.util.UserUtils;
import com.duan.laugh.msg.api.constans.MsgConstants;
import com.duan.laugh.msg.api.pojo.entity.Msg;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.ExtensionElement;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.image.ProcessDiagramGenerator;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 工作流任务service 实现
 *
 * @author duanjw
 */
@Slf4j
@Service
@AllArgsConstructor
public class ActTaskServiceImpl implements ActTaskService {
    private final TaskService taskService;
    private final RuntimeService runtimeService;
    private final RepositoryService repositoryService;
    private final HistoryService historyService;
    private final AmqpTemplate amqpTemplate;
    /**
     * 流程图生成器
     */
    private final ProcessDiagramGenerator processDiagramGenerator;

    @Override
    public IPage getTaskByName(Map<String, Object> params, String name) {
        int page = MapUtil.getInt(params, ActivitiConstants.CURRENT);
        int limit = MapUtil.getInt(params, ActivitiConstants.SIZE);

        TaskQuery taskQuery = taskService.createTaskQuery()
                .taskCandidateOrAssigned(name)
                .taskTenantId(String.valueOf(UserUtils.getUser().getTenantId()));

        IPage result = new Page(page, limit);
        result.setTotal(taskQuery.count());

        List<TaskDTO> taskDTOList = taskQuery.orderByTaskCreateTime().desc()
                .listPage((page - 1) * limit, limit).stream().map(task -> {
                    TaskDTO dto = new TaskDTO();
                    dto.setTaskId(task.getId());
                    dto.setTaskName(task.getName());
                    dto.setProcessInstanceId(task.getProcessInstanceId());
                    dto.setNodeKey(task.getTaskDefinitionKey());
                    dto.setCategory(task.getCategory());
                    dto.setTime(task.getCreateTime());
                    return dto;
                }).collect(Collectors.toList());
        result.setRecords(taskDTOList);
        return result;
    }

    /**
     * 根据流程id分页查询任务
     *
     * @param processId
     * @param params
     * @return
     */
    @Override
    public IPage selectPageByProcessId(String processId, Map<String, Object> params) {
        int page = MapUtil.getInt(params, ActivitiConstants.CURRENT);
        int limit = MapUtil.getInt(params, ActivitiConstants.SIZE);

        TaskQuery taskQuery = taskService.createTaskQuery()
                .processDefinitionId(processId)
                .taskTenantId(String.valueOf(UserUtils.getUser().getTenantId()));

        IPage result = new Page(page, limit);
        result.setTotal(taskQuery.count());

        List<TaskDTO> taskDTOList = taskQuery.orderByTaskCreateTime().desc()
                .listPage((page - 1) * limit, limit).stream().map(task -> {
                    TaskDTO dto = new TaskDTO();
                    dto.setTaskId(task.getId());
                    dto.setTaskName(task.getName());
                    dto.setProcessInstanceId(task.getProcessInstanceId());
                    dto.setNodeKey(task.getTaskDefinitionKey());
                    dto.setCategory(task.getCategory());
                    dto.setTime(task.getCreateTime());
                    return dto;
                }).collect(Collectors.toList());
        result.setRecords(taskDTOList);
        return result;
    }


    /**
     * 根据任务id完成任务
     *
     * @param map
     * @return
     */
    @Override
    public Boolean complete(String id, Map map) {
//
		Task task = taskService.createTaskQuery()
			.taskId(id)
			.singleResult();
        UserTask userTask =(UserTask)repositoryService.getBpmnModel(task.getProcessDefinitionId()).getFlowElement(task.getTaskDefinitionKey());
//        List<FormProperty> formProperties = userTask.getFormProperties();
        // 自定义属性
        final Map<String, List<ExtensionElement>> extensionElementMap = userTask.getExtensionElements();
        final String requestUrl = getExtensionElementValueByKey(extensionElementMap, "request_url");
        final String messageSelect = getExtensionElementValueByKey(extensionElementMap, "message_select");
        final String emailSelect = getExtensionElementValueByKey(extensionElementMap, "email_select");
        // 触发后请求的URL不为空
        if(StrUtil.isNotBlank(requestUrl)) {
            final String[] s = requestUrl.split(" ");
            String response;
            String token = UserUtils.getToken();
            final HttpRequest httpRequest = new HttpRequest(s[1]).method(Method.valueOf(s[0]));
            // 如果http是GET方法，参数放到url后；否则，参数放到body
            if (Method.GET.name().equals(s[0].toUpperCase())) {
                httpRequest.form(map);
            } else {
                httpRequest.body(JSONObject.toJSONString(map));
            }
            // 设置登录人的登录信息并发送http请求
            response = httpRequest.header("Authorization", "Bearer " + token).execute().body();
            log.info("调用业务接口：{}，返回值：{}", httpRequest.getUrl(), response);
        }

        if("1".equals(messageSelect)) {
            log.info("需要发送消息");
            // mq发送消息
            Msg msg = new Msg();
            msg.setRec("one");
            msg.setContent("我是工作流发来的消息，你收到了么");
            msg.setSubject("工作流发来的消息");
            amqpTemplate.convertAndSend(MsgConstants.MQ_QUEUE_SYS_MSG, msg);
        }
        if("1".equals(emailSelect)) {
            log.info("需要发送邮件");
        }
        //        taskService.complete(id, map);

        return null;
    }

    @Override
    public List<CommentDto> getCommentByTaskId(String taskId) {
        //使用当前的任务ID，查询当前流程对应的历史任务ID
        //使用当前任务ID，获取当前任务对象
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();
        //获取流程实例ID
        List<CommentDto> commentDtoList = taskService
                .getProcessInstanceComments(task.getProcessInstanceId())
                .stream().map(comment -> {
                            CommentDto commentDto = new CommentDto();
                            commentDto.setId(comment.getId());
                            commentDto.setTime(comment.getTime());
                            commentDto.setType(comment.getType());
                            commentDto.setTaskId(comment.getTaskId());
                            commentDto.setUserId(comment.getUserId());
                            commentDto.setFullMessage(comment.getFullMessage());
                            commentDto.setProcessInstanceId(comment.getProcessInstanceId());
                            return commentDto;
                        }
                ).collect(Collectors.toList());
        return commentDtoList;
    }

    /**
     * 根据任务id查看流程图
     *
     * @param id
     */
    @Override
    public InputStream viewByTaskId(String id) {
        //使用当前任务ID，获取当前任务对象
        Task task = taskService.createTaskQuery()
                .taskId(id)
                .singleResult();

        String processInstanceId = task.getProcessInstanceId();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        HistoricProcessInstance historicProcessInstance =
                historyService.createHistoricProcessInstanceQuery()
                        .processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = null;
        List<String> executedActivityIdList = new ArrayList<>();
        if (processInstance != null) {
            processDefinitionId = processInstance.getProcessDefinitionId();
            executedActivityIdList = this.runtimeService.getActiveActivityIds(processInstance.getId());
        } else if (historicProcessInstance != null) {
            processDefinitionId = historicProcessInstance.getProcessDefinitionId();

            //高亮已经执行流程节点ID集合
            executedActivityIdList = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .orderByHistoricActivityInstanceId().asc().list()
                    .stream().map(HistoricActivityInstance::getActivityId)
                    .collect(Collectors.toList());
        }

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        return processDiagramGenerator.generateDiagram(
                bpmnModel,
                executedActivityIdList, Collections.emptyList());

    }

    /**
     * 根据扩展属性key获取扩展属性第一个元素的值
     * @param extensionElementMap
     * @param key
     * @return
     */
    private String getExtensionElementValueByKey(Map<String, List<ExtensionElement>> extensionElementMap, String key) {
        if(ObjectUtil.isEmpty(extensionElementMap)) {
            return null;
        }
        final List<ExtensionElement> extensionElements = extensionElementMap.get(key);
        if(extensionElements == null || extensionElements.size() == 0 ) {
            return null;
        }
        return extensionElements.get(0).getElementText();
    }

}
